package order

import (
	"hotel_Manager_Api/model/dbModel"
	"github.com/go-xorm/xorm"
	"hotel_Manager_Api/util"
	"github.com/go-martini/martini"
	"github.com/martini-contrib/encoder"
	"hotel_Manager_Api/model/dto"
	"fmt"
	"github.com/ahmetb/go-linq"
	"hotel_Manager_Api/handler/scheduleManage"
)

func ChangeDesk(params martini.Params,db *xorm.Engine)int  {
	deskOrderId,err := util.ParamaterToInt64(params,"deskOrderId")
	dstDeskId,err := util.ParamaterToInt64(params,"dstDeskId")
	if err!=nil {
		return 400
	}

	session := db.NewSession()
	deskOrder := new(scheduleManage.DeskOrder)
	has,err :=session.ID(deskOrderId).Get(deskOrder)
	if !has ||  deskOrder.OrderStatus > scheduleManage.Begin{
		return 400
	}

	deskOrder.DeskId = dstDeskId
	_,err = session.ID(deskOrder.Id).Update(deskOrder)
	if err!=nil {
		return 500
	}
	return 200
}

func ChangeStatus(paramater martini.Params ,db *xorm.Engine)(int,error)  {
	id,err := util.ParamaterToInt64(paramater,"id")
	if err!= nil{
		return 400,err
	}
	status,err := util.ParamaterToInt16(paramater,"status")
	if err!= nil{
		return 400,err
	}

	_,err = db.Table(new(dbModel.Order)).ID(id).Update(map[string]interface{}{"status":status})
	if err!=nil{
		return 500,err
	}
	return 200,nil
}

func BulkChangeStatus(status []dto.ChangeOrderStatusDto,db *xorm.Engine)(int,error){
	session := db.NewSession()
	defer session.Close()
	if len(status)>0{
		for _,e := range status{
			_,err :=	db.Table(new(dbModel.Order)).ID(e.Id).Update(map[string]interface{}{"status":e.Status})
			if err != nil{
				session.Rollback()
				return  500,err
			}
		}
	}
	err := session.Commit()
	if err!=nil{
		return 500,err
	}
	return 200,nil
}

func GetAllOrders(db *xorm.Engine,enc encoder.Encoder)(int,[]byte,error)  {
	result,err := getAllDeskOrders(db)
	if err!=nil{
		fmt.Print(err)
		return 500,nil,err
	}
	return 200,encoder.Must(enc.Encode(result)),nil
}

func getAllDeskOrders(db *xorm.Engine)([]dto.DeskOrderInfo,error){
	desks := make([]dbModel.Desk,0)
	deskOrders := make([]scheduleManage.DeskOrder,0)
	schedules := make([]dbModel.ScheduleOrder,0)

	foods := make([]dbModel.Food,0)
	orders := make([]dbModel.Order,0)
	units := make([]dbModel.Unit,0)

	db.Find(&desks)
	db.Find(&deskOrders)
	db.Where("enable=?",true).Find(&foods)
	err := db.Find(&orders)
	if err!=nil{
		fmt.Println(err)
	}
	db.Find(&schedules)
	db.Find(&units)

	foodOrders := toFoodOrders(foods,orders)
	joinUnit(foodOrders,units)
	deskOrderResult := joinDeskOrdersSchedules(deskOrders,schedules)
	joinFoodOrders(deskOrderResult,foodOrders)
	result := joinDesk(desks,deskOrderResult)
	return result,nil;
}

func joinDesk(desks []dbModel.Desk,deskOrders []dto.DeskOrderDto)[]dto.DeskOrderInfo  {
	orderResult := make([]dto.DeskOrderInfo,0)

	linq.From(desks).GroupJoinT(linq.From(deskOrders),
		func(desk dbModel.Desk)int64 {return desk.Id},
		func(deskOrder dto.DeskOrderDto)int64 {return deskOrder.DeskId},
		func(desk dbModel.Desk,deskOrder []dto.DeskOrderDto)dto.DeskOrderInfo {
			result := dto.DeskOrderInfo{
				Id:desk.Id,
				Floor:desk.Floor,
				Name:desk.Name,
				ChairCount:desk.ChairCount,
			}
			if len(deskOrder)>0{
				result.DeskOrders = deskOrder
			}
			return result
		}).ToSlice(&orderResult)
		return orderResult
}

func joinFoodOrders(deskOrders []dto.DeskOrderDto,foodOrders []dto.FoodOrder){
	linq.From(deskOrders).GroupJoinT(linq.From(foodOrders),
		func(deskOrder dto.DeskOrderDto)int64 {return deskOrder.Id},
		func(foodOrder dto.FoodOrder)int64 {return foodOrder.DeskOrderId},
		func(deskOrder dto.DeskOrderDto,foodOrders []dto.FoodOrder)dto.DeskOrderDto {
			if len(foodOrders) >0{
				deskOrder.Orders = foodOrders
			}
			return deskOrder
		}).ToSlice(&deskOrders)
}

func joinDeskOrdersSchedules(deskOrders []scheduleManage.DeskOrder,schedules []dbModel.ScheduleOrder)[]dto.DeskOrderDto  {
	deskOrderResult := make([]dto.DeskOrderDto,0)
	linq.From(deskOrders).
		GroupJoinT(linq.From(schedules),
			func(deskOrder scheduleManage.DeskOrder)int64 {return deskOrder.Id},
			func(schedule dbModel.ScheduleOrder)int64{return schedule.DeskOrderId},
		func(deskOrder scheduleManage.DeskOrder,schedule []dbModel.ScheduleOrder)dto.DeskOrderDto {
			result := dto.DeskOrderDto{}
			result.DeskOrder = deskOrder
			if len(schedule)>0{
				result.ScheduleInfo = &schedule[0]
			}
			return result
		}).ToSlice(&deskOrderResult)
		return deskOrderResult
}

func joinUnit(orders []dto.FoodOrder,units []dbModel.Unit)  {
	linq.From(orders).
		JoinT(linq.From(units),
		func(order dto.FoodOrder) int16{return order.UnitId},
		func(unit dbModel.Unit) int16 {return unit.Id},
		func(order dto.FoodOrder,unit dbModel.Unit) dto.FoodOrder {order.Unit = unit.Name;return order}).
			ToSlice(&orders)
}
func toFoodOrders(foods []dbModel.Food,orders []dbModel.Order)  []dto.FoodOrder {
	orderResults := make([]dto.FoodOrder,0)
	linq.From(orders).
		JoinT(linq.From(foods),
			func(order dbModel.Order)int64 {return order.FoodId},
			func(food dbModel.Food)int64 {return food.Id},
			func(order dbModel.Order,food dbModel.Food)dto.FoodOrder {
				result := dto.FoodOrder{
					Id:order.Id,
					FoodId:food.Id,
					Count:order.Count,
					Status:int16(order.Status),
					Name:food.Name,
					Price:food.Price,
					CreateTime:order.CreateTime,
					UnitId:food.UnitId,
					DeskOrderId:order.DeskOrderId,
				}
				return result
			}).ToSlice(&orderResults)
			return orderResults;
}

func DinnerFinish(params martini.Params,db *xorm.Engine)(int,error)  {
	deskId,err := util.ParamaterToInt64(params,"deskId")
	if err!= nil{
		return 400,err
	}
	session := db.NewSession()
	defer session.Close()
	_,err = session.Exec( "insert into finish_order select * from `order` where deskId=?",deskId)
	if err!= nil{
		session.Rollback()
		return 500,nil
	}
	_,err = session.Where("deskId=?",deskId).Delete(dbModel.Order{})
	err = session.Commit()
	if err!= nil{
		session.Rollback()
		return 500,err
	}
	return 200,nil
}